% function [patchTime,coordinates_median,coordinates_median_average,allResults]=...
%     mapPatch(network,localMaps,startNodes,anchorSets)

function [result]=mapPatch(network,localMaps,startNodes,anchorSets,...
    radius,patchNumber,folder,operations)

%This function patches local maps into the global map for all the local maps
%computed for each radius value stored in the localMaps.
%input:
%  network - Nx2 matrix of the network
%  localMaps - computed using localMapComputing.m
%  startNodes - 1xM matrix containing M starting nodes that want to be
%    experimented with
%  anchorSets - SxT matrix containing S anchorSets sets that want to be experimented
%    with. Each anchorSets set has T anchorSets nodes.

startMapPatch=tic;

result.network=network;
result.connectivity=network.networkConnectivityLevel;
result.radius=radius;

numStartNodes=size(startNodes,2);  % number of starting nodes
%numAnchorSets=floor(size(anchorSets,1)/MOD_ANCHORS);  % number of anchorSets sets for testing
numAnchorSets=size(anchorSets,1);

% preallocate
errorsPerStart(numStartNodes,1) = struct(...
    'mean',0,...
    'median',0,...
    'max',0,...
    'min',0,...
    'std',0,...
    'time',0);

errorsPerAnchorSet(numAnchorSets,1) = struct(...
    'mean',0,...
    'median',0,...
    'max',0,...
    'min',0,...
    'std',0,...
    'time',0);

errors(numAnchorSets,numStartNodes) = struct(...
    'mean',0,...
    'median',0,...
    'max',0,...
    'min',0,...
    'std',0,...
    'time',0);
anchorErrors(numAnchorSets,numStartNodes) = struct(...
    'mean',0,...
    'median',0,...
    'max',0,...
    'min',0,...
    'std',0);
coordinateErrors(numAnchorSets,numStartNodes) = struct(...
    'mean',0,...
    'median',0,...
    'max',0,...
    'min',0,...
    'std',0);

bestNodes=zeros(numAnchorSets,numStartNodes);
worstNodes=zeros(numAnchorSets,numStartNodes);

for startNodeIndex=1:numStartNodes   % for each starting node
    folderName=sprintf('%s/patchedMaps',folder);
    filename=sprintf('%s/patchedMaps_startNode%i_index-%i.mat',...
        folderName,startNodes(startNodeIndex),startNodeIndex);
    if (exist(folderName,'dir') == 0)
        mkdir(folderName);
    end
    if (exist(filename,'file') == 0)
        fprintf(1,'+++ %s Start Node %i (%i of %i)\n', patchNumber, ...
            startNodes(startNodeIndex), startNodeIndex, numStartNodes);
        [localMaps,rawResult]=mapVitPatch(network,localMaps,startNodeIndex);
        save(filename,'localMaps','rawResult');
    else
        load(filename);
    end
    refineResult=rawResult; %no refinement
    
    for anchorSetIndex=1:numAnchorSets % for each anchorSets set
        startAnchor=tic;
        anchorNodes=anchorSets(anchorSetIndex,:);
        label=sprintf('StartNode%i_AnchorSet%i',startNodeIndex,anchorSetIndex);
        [result,e,ae,ce]=calculateErrors(network, radius,localMaps(startNodeIndex),...
            refineResult,operations,folder,label,...
            result,anchorSetIndex,anchorNodes);
        errors(anchorSetIndex,startNodeIndex)=e;
        anchorErrors(anchorSetIndex,startNodeIndex)=ae;
        coordinateErrors(anchorSetIndex,startNodeIndex)=ce;
         
        result.ixys(anchorSetIndex,startNodeIndex)=...
            calculateErrorsIndependentXY(...
            network, radius,localMaps(startNodeIndex),...
            refineResult,operations,folder,label,...
            anchorSetIndex,anchorNodes);
        
        fprintf(1,'++++ %s Patched Maps with Start #%i/%i, Anchor Set %i/%i in %.2f sec\n', ...
            patchNumber,startNodeIndex,numStartNodes, anchorSetIndex, numAnchorSets, toc(startAnchor));
    end
    
    errorsPerStart(startNodeIndex)=struct(...
        'mean',mean([errors(:,startNodeIndex).mean]),...
        'median',mean([errors(:,startNodeIndex).median]),...
        'max',mean([errors(:,startNodeIndex).max]),...
        'min',mean([errors(:,startNodeIndex).min]),...
        'std',mean([errors(:,startNodeIndex).std]),...
        'time',mean([errors(:,startNodeIndex).time]));
    clear A;
    clear times;
    
end % for startNodeIndex

for a=1:numAnchorSets % for each anchorSet
    errorsPerAnchorSet(a,1)=struct(...
        'mean',sum([errors(a,:).mean]),...
        'median',sum([errors(a,:).median]),...
        'max',sum([errors(a,:).max]),...
        'min',sum([errors(a,:).min]),...
        'std',sum([errors(a,:).std]),...
        'time',sum([errors(a,:).time]));
    
%     result.ixy.errorsPerAnchorSet(a,1)=struct(...
%         'mean',sum([result.ixys(a,:).errors.mean]),...
%         'median',sum([result.ixys(a,:).errors.median]),...
%         'max',sum([result.ixys(a,:).errors.max]),...
%         'min',sum([result.ixys(a,:).errors.min]),...
%         'std',sum([result.ixys(a,:).errors.std]),...
%         'time',sum([result.ixys(a,:).errors.time]));    
end

% Average over the start nodes
result.errors=errors;
result.anchorErrors=anchorErrors;
result.coordinateErrors=coordinateErrors;
result.errorsPerStart=errorsPerStart;
result.errorsPerAnchorSet=errorsPerAnchorSet;
result.bestNodesPerAnchorSet=bestNodes;
result.worstNodesPerAnchorSet=worstNodes;
result.mapPatchTime=toc(startMapPatch);

return

end

function [result,errors,anchorErrors,coordinatesError] = ...
    calculateErrors(network, radius,startNode,refineResult,operations,...
    folder,label,result,anchorSetIndex,anchorNodes)

[mappedResult,transform,dissimilarity,reflect]=...
    transformMap(network.points, refineResult, anchorNodes, operations,folder,label);
resultNode=compareMaps(network, startNode, mappedResult, radius);

differenceVector=resultNode.differenceVector;
distanceVector=resultNode.distanceVector;
result.patchedMap(anchorSetIndex)=resultNode;
result.dissimilarity(anchorSetIndex)=max(dissimilarity);
result.transform(anchorSetIndex)=transform(1);
result.reflect=reflect;
% Remove the anchor node differences
%         for i=1:size(anchorNodes,2)
%             % Assumes anchorNodes are in order
%             if (anchorNodes(1,i) == 1)
%                 index=1;
%             else
%                 index=anchorNodes(1,i)-i-1;
%             end
%             differenceVector(index,:)=[];
%         end
coordinatesError = struct('mean',mean(differenceVector)/radius,...
    'median',median(differenceVector)/radius,...
    'max',max(differenceVector)/radius,...
    'min',min(differenceVector)/radius,...
    'std',std(differenceVector)/radius);

%         for i=1:size(anchorNodes,2)
%             fprintf('Anchor Node Error: %i - %.2f\n', anchorNodes(i),differenceVector(i));
%         end
errors = struct(...
    'mean',mean(distanceVector/radius),...
    'median',median(distanceVector/radius),...
    'max',max(distanceVector/radius),...
    'min',min(distanceVector/radius),...
    'std',std(distanceVector/radius),...
    'time',resultNode.map_patchTime);

anchorErrors = struct(...
    'mean',max(mean(distanceVector(anchorNodes,:))),...
    'median',max(median(distanceVector(anchorNodes,:))),...
    'max',max(max(distanceVector(anchorNodes,:))),...
    'min',max(min(distanceVector(anchorNodes,:))),...
    'std',max(std(distanceVector(anchorNodes,:))));
end

function [ixy] = ...
    calculateErrorsIndependentXY(network, radius,startNode,refineResult,operations,...
    folder,label,anchorSetIndex,anchorNodes)

[mappedResult,transform,dissimilarity,reflect]=...
    transformMapIndependentXY(network.points, refineResult, anchorNodes, operations,folder,label);
resultNode=compareMaps(network, startNode, mappedResult, radius);

differenceVector=resultNode.differenceVector;
ixy.patchedMap(anchorSetIndex)=resultNode;
ixy.dissimilarity(anchorSetIndex)=max(dissimilarity);
ixy.transform(anchorSetIndex)=transform(1);
ixy.reflect=reflect;
% Remove the anchor node differences
%         for i=1:size(anchorNodes,2)
%             % Assumes anchorNodes are in order
%             if (anchorNodes(1,i) == 1)
%                 index=1;
%             else
%                 index=anchorNodes(1,i)-i-1;
%             end
%             differenceVector(index,:)=[];
%         end
ixy.coordinatesError = struct('mean',mean(differenceVector)/radius,...
    'median',median(differenceVector)/radius,...
    'max',max(differenceVector)/radius,...
    'min',min(differenceVector)/radius,...
    'std',std(differenceVector)/radius);

%         for i=1:size(anchorNodes,2)
%             fprintf('Anchor Node Error: %i - %.2f\n', anchorNodes(i),differenceVector(i));
%         end
ixy.errors = struct(...
    'mean',sum(ixy.coordinatesError.mean),...
    'median',sum(ixy.coordinatesError.median),...
    'max',sum(ixy.coordinatesError.max),...
    'min',sum(ixy.coordinatesError.min),...
    'std',sum(ixy.coordinatesError.std),...
    'time',resultNode.map_patchTime);

ixy.anchorErrors = struct(...
    'mean',min(mean(differenceVector(anchorNodes,:))),...
    'median',min(median(differenceVector(anchorNodes,:))),...
    'max',min(max(differenceVector(anchorNodes,:))),...
    'min',min(min(differenceVector(anchorNodes,:))),...
    'std',min(std(differenceVector(anchorNodes,:))));

end

